import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
import * as XLSX from 'xlsx';
import { BehaviorSubject, Subject, interval, Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';


import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { NzAlertModule } from 'ng-zorro-antd/alert';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzTagModule } from 'ng-zorro-antd/tag';
import { NzModalModule } from 'ng-zorro-antd/modal';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
import { NzSelectModule } from 'ng-zorro-antd/select';
import { NzIconModule } from 'ng-zorro-antd/icon';

import { setStrategyType, getStrategyType } from '../../utils/keyTypeStore'

interface Category {
  id: string;
  name: string;
  description?: string;
  bookCount: number;
  status: 'active' | 'disabled';
  level: number;
  createTime: Date;
  updateTime: Date;
  children: Category[];
}

interface Book {
  id: number;
  title: string;
  author: string;
  status: string;
  expanded: boolean;
  isbn: string;
  publisher: string;
  publishDate: string;
  description: string;
  price: string;
  rating: string;
}




declare global {
  interface Window {
    domTrackStats: {
      created: number;
      destroyed: number;
      reused: number;
      reset: () => void;
      incrementCreated: () => void;
      incrementDestroyed: () => void;
    };
  }
}

if (!window.domTrackStats) {
  window.domTrackStats = {
    created: 0,
    destroyed: 0,
    reused: 0,
    reset() {
      this.created = 0;
      this.destroyed = 0;
      this.reused = 0;
    },
    incrementCreated() {
      this.created++;
    },
    incrementDestroyed() {
      this.destroyed++;
    }
  };
}

@Component({
  selector: 'app-nested-list',
  imports: [
    CommonModule,
    FormsModule,
    NzAlertModule,
    NzFormModule,
    NzTagModule,
    NzModalModule,
    NzInputModule,
    NzButtonModule,
    NzInputNumberModule,
    NzSelectModule,
    NzIconModule,
  ],
  templateUrl: './nested-list.component.html',
  styleUrls: ['./nested-list.component.less'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class NestedListComponent implements OnInit, OnDestroy {
  categoryTree: Category[] = [];
  loading = false;
  expandedKeys: string[] = [];
  editDialogVisible = false;
  editingCategory: Category | null = null;
  currentCategory: Category = {} as Category;
  books: Book[] = [];
  nextId = 1;
  keyType: 'id' | 'index' | 'none' = 'id';
  renderTime: string | null = null;
  domTrackStats = window.domTrackStats;
  showAcademicTestList = false;
  academicBooks: Book[] = [];


  private _keyStrategy = new BehaviorSubject<'id' | 'index' | 'none'>('id');
  keyStrategy$ = this._keyStrategy.asObservable();
  keyStrategy: 'id' | 'index' | 'none' = 'id';

  private destroy$ = new Subject<void>();

  constructor(
    private message: NzMessageService,
    private modal: NzModalService,
    private cdr: ChangeDetectorRef
  ) { }

  ngOnInit(): void {
    this.resetCategories();
    this.generateBooks(10);


    this.keyStrategy$.pipe(takeUntil(this.destroy$)).subscribe(strategy => {
      this.keyStrategy = strategy;
      this.cdr.detectChanges();
    });
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }


  get totalCategories(): number {
    return this.countNodes(this.categoryTree);
  }

  get maxDepth(): number {
    return this.getMaxDepth(this.categoryTree);
  }

  get totalBooks(): number {
    return this.sumBookCount(this.categoryTree);
  }

  get reuseRate(): string {
    const N = this.academicBooks.length;
    if (N === 0) return '0.00';

    const reusedCount = N - this.domTrackStats.destroyed;
    return (reusedCount >= 0 && N > 0 ? (reusedCount / N) * 100 : 0).toFixed(2);
  }




  // updateKeyStrategy(strategy: 'id' | 'index' | 'none'): void {
  //   this._keyStrategy.next(strategy);
  // }


  toggleKeyType(value:  'id' | 'index' | 'none') {
    this.keyType = value;
    this._keyStrategy.next(value);

    setStrategyType(value)
    this.message.info(`已切换到${value}`)
  }


  trackById(index: number, item: any): string | number | null {
    switch (this.keyType) {
      case 'id':
        return item.id;
      case 'index':
        return index;
      case 'none':
        return null;
      default:
        return item.id;
    }
  }

  countNodes(nodes: Category[]): number {
    let count = 0;
    nodes.forEach(node => {
      count++;
      if (node.children && node.children.length > 0) {
        count += this.countNodes(node.children);
      }
    });
    return count;
  }

  getMaxDepth(nodes: Category[], currentDepth = 1): number {
    if (!nodes || nodes.length === 0) return 0;
    let maxDepth = currentDepth;
    nodes.forEach(node => {
      if (node.children && node.children.length > 0) {
        const childDepth = this.getMaxDepth(node.children, currentDepth + 1);
        maxDepth = Math.max(maxDepth, childDepth);
      }
    });
    return maxDepth;
  }

  sumBookCount(nodes: Category[]): number {
    let total = 0;
    nodes.forEach(node => {
      total += node.bookCount || 0;
      if (node.children && node.children.length > 0) {
        total += this.sumBookCount(node.children);
      }
    });
    return total;
  }

  generateCategoryId(): string {
    return `cat_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  createCategory(name: string, description = '', bookCount = 0, level = 1): Category {
    return {
      id: this.generateCategoryId(),
      name: name,
      description: description,
      bookCount: bookCount,
      status: 'active',
      level: level,
      createTime: new Date(),
      updateTime: new Date(),
      children: []
    };
  }

  findCategoryAndOperate(nodes: Category[], categoryId: string, operation: (nodes: Category[], index: number) => void): boolean {
    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].id === categoryId) {
        operation(nodes, i);
        return true;
      }
      if (nodes[i].children && nodes[i].children.length > 0) {
        if (this.findCategoryAndOperate(nodes[i].children, categoryId, operation)) {
          return true;
        }
      }
    }
    return false;
  }

  addRootCategory(): void {
    const newCategory = this.createCategory('新根分类', '这是一个新的根分类', 10);
    this.categoryTree.push(newCategory);
    this.cdr.detectChanges();
    this.message.success('根分类添加成功！');
  }

  addSubCategory(parentCategory: Category): void {
    const newCategory = this.createCategory('新子分类', `这是${parentCategory.name}的子分类`, 5, parentCategory.level + 1);
    if (!parentCategory.children) {
      parentCategory.children = [];
    }
    parentCategory.children.push(newCategory);
    if (!this.isExpanded(parentCategory.id)) {
      this.toggleExpand(parentCategory);
    }
    this.cdr.detectChanges();
    this.message.success('子分类添加成功！');
  }

  editCategory(category: Category): void {
    this.editingCategory = category;
    this.currentCategory = { ...category };
    this.editDialogVisible = true;
  }

  saveCategory(): void {
    if (this.editingCategory) {
      Object.assign(this.editingCategory, {
        ...this.currentCategory,
        updateTime: new Date()
      });




      this.categoryTree = [...this.categoryTree];
    } else {
      console.warn('Attempted to save a new category via edit dialog without proper context.');
    }
    this.editDialogVisible = false;
    this.editingCategory = null;
    this.message.success('分类已保存！');
    this.cdr.detectChanges();
  }

  deleteCategory(categoryToDelete: Category): void {
    this.modal.confirm({
      nzTitle: `确定要删除分类"${categoryToDelete.name}"及其所有子分类吗？`,
      nzContent: '删除后不可恢复！',
      nzOkText: '确定',
      nzOkType: 'primary',
      nzCancelText: '取消',
      nzOnOk: () => {
        const deleteOperation = (nodes: Category[], index: number) => nodes.splice(index, 1);
        this.findCategoryAndOperate(this.categoryTree, categoryToDelete.id, deleteOperation);
        this.message.success('删除成功！');
        this.categoryTree = [...this.categoryTree];
        this.cdr.detectChanges();
      },
      nzOnCancel: () => {
        this.message.info('已取消删除');
      }
    });
  }

  resetCategories(): void {
    this.categoryTree = this.generateNestedCategories(7, 10, 10, 50, 50);
    this.expandedKeys = this.categoryTree.map(cat => cat.id);
    this.cdr.detectChanges();
  }

  generateNestedCategories(level1Count: number, minLevel2Children: number, maxLevel2Children: number, minLevel3Children: number, maxLevel3Children: number): Category[] {
    const categories: Category[] = [];
    const level1Names = [
      '文学艺术', '科学技术', '历史地理', '社会科学', '教育培训',
      '生活时尚', '少儿读物', '经济管理', '医学健康', '哲学宗教',
      '计算机与互联网', '法律', '军事', '体育', '旅游'
    ];
    const level2Names = [
      '小说', '诗歌', '散文', '传记', '艺术理论', '绘画', '音乐',
      '物理学', '化学', '生物学', '数学', '天文学', '地球科学',
      '中国历史', '世界历史', '地理学', '考古学',
      '政治学', '经济学', '社会学', '心理学', '管理学',
      '教育学', '职业技能', '外语学习',
      '烹饪美食', '健康养生', '时尚穿搭', '家居生活',
      '童话故事', '儿童文学', '益智游戏',
      '宏观经济', '微观经济', '金融投资', '市场营销',
      '中医', '西医', '营养学', '疾病预防',
      '哲学', '宗教学', '伦理学'
    ];
    const level3Names = [
      '现代小说', '古典文学', '外国文学', '中国文学', '科幻小说', '推理小说',
      '唐诗宋词', '现代诗',
      '中国近现代史', '世界近代史', '古代史', '当代史',
      'C++编程', 'Java开发', 'Python数据分析', 'JavaScript前端', '人工智能基础', '机器学习实践',
      '高等数学', '线性代数',
      '烹饪技巧', '烘焙入门',
      '儿童绘本', '睡前故事'
    ];

    for (let i = 0; i < level1Count; i++) {
      const level1: Category = {
        id: this.generateCategoryId(),
        name: `${level1Names[i % level1Names.length]} - ${i + 1}`,
        bookCount: Math.floor(Math.random() * 10 + 1),
        status: 'active',
        level: 1,
        createTime: new Date(),
        updateTime: new Date(),
        children: []
      };
      for (let j = 0; j < minLevel2Children; j++) {
        const level2: Category = {
          id: this.generateCategoryId(),
          name: `${level2Names[j % level2Names.length]} - ${i + 1}-${j + 1}`,
          bookCount: Math.floor(Math.random() * 10 + 1),
          status: 'active',
          level: 2,
          createTime: new Date(),
          updateTime: new Date(),
          children: []
        };
        for (let k = 0; k < minLevel3Children; k++) {
          const level3: Category = {
            id: this.generateCategoryId(),
            name: `${level3Names[k % level3Names.length]} - ${i + 1}-${j + 1}-${k + 1}`,
            bookCount: Math.floor(Math.random() * 10 + 1),
            status: 'active',
            level: 3,
            createTime: new Date(),
            updateTime: new Date(),
            children: []
          };
          level2.children.push(level3);
        }
        level1.children.push(level2);
      }
      categories.push(level1);
    }
    return categories;
  }

  toggleExpand(category: Category): void {
    const index = this.expandedKeys.indexOf(category.id);
    if (index > -1) {
      this.expandedKeys.splice(index, 1);
      this.collapseChildren(category);
    } else {
      this.expandedKeys.push(category.id);
    }
    this.cdr.detectChanges();
  }

  collapseChildren(category: Category): void {
    if (category.children) {
      category.children.forEach(child => {
        const index = this.expandedKeys.indexOf(child.id);
        if (index > -1) {
          this.expandedKeys.splice(index, 1);
        }
        this.collapseChildren(child);
      });
    }
    this.cdr.detectChanges();
  }

  isExpanded(categoryId: string): boolean {
    return this.expandedKeys.includes(categoryId);
  }

  expandAll(): void {
    const expandNode = (node: Category) => {
      if (!this.expandedKeys.includes(node.id)) {
        this.expandedKeys.push(node.id);
      }
      if (node.children) {
        node.children.forEach(expandNode);
      }
    };
    this.categoryTree.forEach(expandNode);
    this.cdr.detectChanges();
  }

  collapseAll(): void {
    this.expandedKeys = [];
    this.cdr.detectChanges();
  }

  quickDemo(): void {
    this.message.info('执行快速演示...');
    this.resetCategories();
    setTimeout(() => {
      this.addRootCategory();
      this.cdr.detectChanges();
    }, 500);
  }

  getStatusType(status: 'active' | 'disabled'): 'success' | 'error' | 'default' {
    switch (status) {
      case 'active': return 'success';
      case 'disabled': return 'error';
      default: return 'default';
    }
  }

  viewCategoryBooks(category: Category): void {
    this.message.info(`查看分类 "${category.name}" 下的图书`);
  }




  handleDrop(draggingNode: any, dropNode: any, dropType: string): void {
    this.message.info(`拖拽操作：${draggingNode.data.name} 拖拽到 ${dropNode.data.name}，类型：${dropType}`);
  }

  generateMockBook(): Book {
    const realTitles = [
      '百年孤独', '1984', '动物农场', '小王子', '围城', '活着', '三体', '人类简史', '情商', '影响力',
      '乌合之众', '君主论', '资治通鉴', '红楼梦', '西游记', '水浒传', '三国演义', '呐喊', '朝花夕拾', '边城'
    ];
    const realAuthors = [
      '加西亚·马尔克斯', '乔治·奥威尔', '安托万·德·圣-埃克苏佩里', '钱钟书', '余华', '刘慈欣', '尤瓦尔·赫拉利', '丹尼尔·戈尔曼', '古斯塔夫·勒庞', '尼科洛·马基雅维利',
      '司马光', '曹雪芹', '吴承恩', '施耐庵', '罗贯中', '鲁迅', '沈从文'
    ];
    const realPublishers = [
      '新经典文化', '上海译文出版社', '人民文学出版社', '北京十月文艺出版社', '重庆出版社',
      '中信出版集团', '浙江人民出版社', '商务印书馆', '译林出版社', '南海出版公司'
    ];
    const descriptions = [
      '本书详细介绍了相关技术原理与实践。',
      '适合初学者和进阶开发者阅读。',
      '内容涵盖理论与实战案例。',
      '帮助读者快速掌握核心知识。'
    ];
    return {
      id: this.nextId++,
      title: realTitles[Math.floor(Math.random() * realTitles.length)],
      author: realAuthors[Math.floor(Math.random() * realAuthors.length)],
      status: '在架',
      expanded: false,
      isbn: '978' + Math.floor(1000000000 + Math.random() * 9000000000),
      publisher: realPublishers[Math.floor(Math.random() * realPublishers.length)],
      publishDate: `202${Math.floor(Math.random() * 4 + 1)}-0${Math.floor(Math.random() * 9 + 1)}-15`,
      description: descriptions[Math.floor(Math.random() * descriptions.length)],
      price: (Math.random() * 100 + 20).toFixed(2),
      rating: (Math.random() * 2 + 3).toFixed(1)
    };
  }

  generateBooks(count = 10): void {
    this.nextId = 1;
    this.books = Array.from({ length: count }, () => this.generateMockBook());
    this.cdr.detectChanges();
  }

  addItem(): void {
    const newItem = this.generateMockBook();
    this.books.splice(this.books.length / 2, 0, newItem);
    this.books = [...this.books];
    this.cdr.detectChanges();
  }

  removeItem(): void {
    if (this.books.length > 0) {
      const randomIndex = Math.floor(Math.random() * this.books.length);
      this.books.splice(randomIndex, 1);
      this.books = [...this.books];
      this.cdr.detectChanges();
    }
  }

  shuffleList(): void {
    for (let i = this.books.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [this.books[i], this.books[j]] = [this.books[j], this.books[i]];
    }
    this.books = [...this.books];
    this.cdr.detectChanges();
  }

  insertRandomBook(): void {
    const idx = Math.floor(Math.random() * (this.books.length + 1));
    this.books.splice(idx, 0, this.generateMockBook());
    this.books = [...this.books];
    this.cdr.detectChanges();
  }

  deleteRandomBook(): void {
    if (this.books.length === 0) return;
    const idx = Math.floor(Math.random() * this.books.length);
    this.books.splice(idx, 1);
    this.books = [...this.books];
    this.cdr.detectChanges();
  }

  replaceAllBooks(): void {
    const len = this.books.length;
    this.books = Array.from({ length: len }, () => this.generateMockBook());
    this.cdr.detectChanges();
  }

  appendToEnd(): void {
    this.books.push(this.generateMockBook());
    this.books = [...this.books];
    this.cdr.detectChanges();
  }

  stepInsert(): void {
    for (let i = 0; i < 10; i++) {
      this.books.splice(i * 2, 0, this.generateMockBook());
    }
    this.books = [...this.books];
    this.cdr.detectChanges();
  }

  insertToMiddle(): void {
    const mid = Math.floor(this.books.length / 2);
    this.books.splice(mid, 0, this.generateMockBook());
    this.books = [...this.books];
    this.cdr.detectChanges();
  }

  partialUpdate(): void {
    for (let i = 0; i < 10 && this.books.length > 0; i++) {
      const idx = Math.floor(Math.random() * this.books.length);

      this.books[idx] = { ...this.books[idx], title: this.books[idx].title + '_更新' };
    }
    this.books = [...this.books];
    this.cdr.detectChanges();
  }

  preciseMeasure(): void {
    performance.clearMarks();
    performance.clearMeasures();
    performance.mark('start-render');
    setTimeout(() => {
      requestAnimationFrame(() => {
        performance.mark('end-render');
        performance.measure('render', 'start-render', 'end-render');
        const measures = performance.getEntriesByName('render');
        if (measures.length > 0) {
          this.renderTime = measures[0].duration.toFixed(2);
        }
        this.cdr.detectChanges();
      });
    }, 0);
  }

  async measureOperation(operationFn: () => void): Promise<string> {
    return new Promise(resolve => {
      requestAnimationFrame(() => {
        performance.clearMarks();
        performance.clearMeasures();
        performance.mark('op-start');

        operationFn();
        this.cdr.detectChanges();

        setTimeout(() => {
          requestAnimationFrame(() => {
            performance.mark('op-end');
            performance.measure('op-duration', 'op-start', 'op-end');
            const measure = performance.getEntriesByName('op-duration')[0];
            const duration = measure ? measure.duration.toFixed(2) : '0.00';
            this.renderTime = duration;
            this.cdr.detectChanges();
            resolve(duration);
          });
        }, 0);
      });
    });
  }

  async performAcademicBookOperationAndMeasure(keyType: 'id' | 'index' | 'none', operationName: string, operationFn: () => void) {
    console.log(`performAcademicBookOperationAndMeasure: Starting test for KeyType: ${keyType}, Operation: ${operationName}`);

    this.keyType = keyType;
    this.showAcademicTestList = true;
    this.renderTime = null;
    this.cdr.detectChanges();

    this.academicBooks = [];
    this.cdr.detectChanges();
    await this.sleep(50);

    if (window.domTrackStats) {
      window.domTrackStats.reset();
    } else {
      console.error("window.domTrackStats is not defined!");
      return { '测试类型': keyType, '操作类型': operationName, '渲染时间(ms)': 'Error', '总耗时(ms)': '0', 'DOM创建数': 0, 'DOM复用数': 0, 'DOM销毁数': 0, 'DOM复用率(%)': '0.00', '列表项数量': 0, '测试时间': new Date().toLocaleString() };
    }

    const totalTimeStart = performance.now();

    if (!operationName.startsWith('生成')) {
      this.generateAcademicBooks(500);
      this.cdr.detectChanges();
      await this.sleep(50);
      if (window.domTrackStats) {
        window.domTrackStats.reset();
      }
    }

    const renderTime = await this.measureOperation(operationFn);
    const totalTime = (performance.now() - totalTimeStart).toFixed(2);

    const createdCount = window.domTrackStats ? window.domTrackStats.created : 0;
    const reusedCount = window.domTrackStats ? window.domTrackStats.reused : 0;
    const destroyedCount = window.domTrackStats ? window.domTrackStats.destroyed : 0;
    const currentAcademicListLength = this.academicBooks.length;






    const reuseRatePercentage = (currentAcademicListLength > 0 ? ((currentAcademicListLength - destroyedCount) / currentAcademicListLength) * 100 : 0).toFixed(2);



    this.domTrackStats.created = createdCount;
    this.domTrackStats.destroyed = destroyedCount;
    this.domTrackStats.reused = currentAcademicListLength - destroyedCount;
    this.cdr.detectChanges();


    return {
      '测试类型': keyType,
      '操作类型': operationName,
      '渲染时间(ms)': renderTime,
      '总耗时(ms)': totalTime,
      'DOM创建数': createdCount,
      'DOM复用数': reusedCount,
      'DOM销毁数': destroyedCount,
      'DOM复用率(%)': reuseRatePercentage,
      '列表项数量': currentAcademicListLength,
      '测试时间': new Date().toLocaleString()
    };
  }









  async autoTestReuse(): Promise<any> {
    console.log('autoTestReuse: Starting test...');
    if (window.domTrackStats) {
      window.domTrackStats.reset();
    } else {
      console.error("window.domTrackStats is not defined!");
      return { created: 0, reused: 0, destroyed: 0, reuseRate: '0.00', totalItems: 0 };
    }

    this.showAcademicTestList = true;
    this.academicBooks = [];
    this.cdr.detectChanges();
    await this.sleep(100);


    this.academicBooks = Array.from({ length: 100 }, () => this.generateMockBook());
    this.cdr.detectChanges();
    await this.sleep(100);

    const initialCreated = window.domTrackStats.created;
    const initialDestroyed = window.domTrackStats.destroyed;
    window.domTrackStats.reset();

    let operationFn: () => void;
    let operationName: string;

    if (this.keyType === 'id') {
      operationFn = () => this.shuffleAcademicBooks();
      operationName = '打乱顺序 (ID Key)';
    } else {

      const currentLength = this.academicBooks.length;
      operationFn = () => {
        this.academicBooks = Array.from({ length: currentLength }, () => this.generateMockBook());
        this.cdr.detectChanges();
      };
      operationName = '替换所有 (Index/None Key)';
    }

    const result = await this.performAcademicBookOperationAndMeasure(this.keyType, operationName, operationFn);


    this.domTrackStats.created = result['DOM创建数'];
    this.domTrackStats.destroyed = result['DOM销毁数'];
    this.domTrackStats.reused = result['DOM复用数'];
    this.cdr.detectChanges();

    this.showAcademicTestList = false;
    this.academicBooks = [];
    this.cdr.detectChanges();
    await this.sleep(500);

    return result;
  }

  shuffleAcademicBooks(): void {
    for (let i = this.academicBooks.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [this.academicBooks[i], this.academicBooks[j]] = [this.academicBooks[j], this.academicBooks[i]];
    }
    this.academicBooks = [...this.academicBooks];
    this.cdr.detectChanges();
  }

  async autoTestBatchAndExportExcel(): Promise<void> {
    const testCases = [
      { name: 'ID作为Key', keyType: 'id' as 'id' },
      { name: 'Index作为Key', keyType: 'index' as 'index' },
      { name: '无Key', keyType: 'none' as 'none' }
    ];

    const results: any[] = [];
    const operations = [
      { name: '生成100本', fn: (count = 100) => this.generateAcademicBooks(count), isGenerate: true },
      { name: '生成1000本', fn: (count = 1000) => this.generateAcademicBooks(count), isGenerate: true },
      { name: '打乱顺序', fn: () => this.shuffleAcademicBooks(), isGenerate: false },
      { name: '插入元素', fn: () => this.insertRandomAcademicBook(), isGenerate: false },
      { name: '删除元素', fn: () => this.deleteRandomAcademicBook(), isGenerate: false },
      { name: '替换所有', fn: () => this.replaceAllAcademicBooks(), isGenerate: false },
      { name: '尾部追加', fn: () => this.appendToEndAcademicBook(), isGenerate: false },
      { name: '中间插入', fn: () => this.insertToMiddleAcademicBook(), isGenerate: false },
      { name: '局部更新', fn: () => this.partialUpdateAcademicBook(), isGenerate: false }
    ];

    for (const testCase of testCases) {
      this.message.info(`开始测试: ${testCase.name}`);

      for (const operation of operations) {

        this.academicBooks = [];
        this.cdr.detectChanges();
        await this.sleep(50);

        const opFn = operation.isGenerate ? () => operation.fn(parseFloat(operation.name.replace('生成', '').replace('本', ''))) : operation.fn;
        const data = await this.performAcademicBookOperationAndMeasure(testCase.keyType, operation.name, opFn);

        results.push(data);

        await this.sleep(500);
      }
    }

    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.json_to_sheet(results);

    const colWidths = [
      { wch: 15 },
      { wch: 15 },
      { wch: 15 },
      { wch: 15 },
      { wch: 15 },
      { wch: 15 },
      { wch: 15 },
      { wch: 15 },
      { wch: 15 },
      { wch: 20 }
    ];
    ws['!cols'] = colWidths;

    XLSX.utils.book_append_sheet(wb, ws, 'DOM性能测试结果');

    const fileName = `DOM性能测试结果_${new Date().toISOString().slice(0, 19).replace(/[:]/g, '-')}.xlsx`;
    XLSX.writeFile(wb, fileName);

    this.message.success('测试完成，数据已导出到Excel文件');
  }

  sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  exportReuseStatsToExcel(): void {
    const stats = [{
      created: window.domTrackStats.created,
      reused: window.domTrackStats.reused,
      destroyed: window.domTrackStats.destroyed,
      reuseRate: this.reuseRate + '%',
      time: new Date().toLocaleString()
    }];

    const currentTotalItems = this.academicBooks.length;
    const currentReused = currentTotalItems - window.domTrackStats.destroyed;
    stats[0].reused = currentReused;

    const ws = XLSX.utils.json_to_sheet(stats);
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, '复用统计');
    XLSX.writeFile(wb, `reuse-stats-${Date.now()}.xlsx`);
    this.message.success('统计数据已导出为Excel！');
  }

  generateAcademicBooks(count: number): void {
    this.nextId = 1;
    this.academicBooks = Array.from({ length: count }, () => this.generateMockBook());
    this.cdr.detectChanges();
  }

  insertRandomAcademicBook(): void {
    const randomIndex = Math.floor(Math.random() * (this.academicBooks.length + 1));
    this.academicBooks.splice(randomIndex, 0, this.generateMockBook());
    this.academicBooks = [...this.academicBooks];
    this.cdr.detectChanges();
  }

  deleteRandomAcademicBook(): void {
    if (this.academicBooks.length === 0) return;
    const randomIndex = Math.floor(Math.random() * this.academicBooks.length);
    this.academicBooks.splice(randomIndex, 1);
    this.academicBooks = [...this.academicBooks];
    this.cdr.detectChanges();
  }

  replaceAllAcademicBooks(): void {
    const len = this.academicBooks.length > 0 ? this.academicBooks.length : 100;
    this.academicBooks = Array.from({ length: len }, () => this.generateMockBook());
    this.cdr.detectChanges();
  }

  appendToEndAcademicBook(): void {
    this.academicBooks.push(this.generateMockBook());
    this.academicBooks = [...this.academicBooks];
    this.cdr.detectChanges();
  }

  insertToMiddleAcademicBook(): void {
    const mid = Math.floor(this.academicBooks.length / 2);
    this.academicBooks.splice(mid, 0, this.generateMockBook());
    this.academicBooks = [...this.academicBooks];
    this.cdr.detectChanges();
  }

  partialUpdateAcademicBook(): void {
    if (this.academicBooks.length === 0) return;
    const idx = Math.floor(Math.random() * this.academicBooks.length);

    this.academicBooks[idx] = { ...this.academicBooks[idx], title: this.academicBooks[idx].title + '_更新' };
    this.academicBooks = [...this.academicBooks];
    this.cdr.detectChanges();
  }
}

